package gui;

import filereaders.Factory;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.util.ResourceBundle;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextArea;
import javax.swing.JTextField;


/**
 * Demo program to show many of the awt events that can be generated.
 * 
 * Illustrates XXXListeners for consuming several types of events including
 * semantic events (e.g., ActionEvent) and low-level events (e.g., FocusEvent)
 * 
 * @author Owen Astrachan
 * @author Robert C. Duvall
 * @author rwb10
 */
@SuppressWarnings("serial")
public class Canvas extends JFrame {
    private static final int GRAPH_WIDTH = 800;
    private static final int GRAPH_HIGHT = 500;
    private static final int FIELD_SIZE = 6;
    private static final String SCATTER_OPTION = "OpenScatter";
    private static final String LINE_OPTION = "OpenLine";
    // most GUI components will be temporary variables,
    // only store components you need to refer to later
    private JTextArea myTextArea;
    private JFileChooser myChooser;
    private JComponent myGraph;
    private Axis myAxis;
    private Factory myFactory;

    // get strings from resource file
    private ResourceBundle myResources;

    // in this example, the listeners can be reused by many
    // components, so keep track of them
    private ActionListener myActionListener;
    private KeyListener myKeyListener;
    private MouseListener myMouseListener;
    private MouseMotionListener myMouseMotionListener;
    private FocusListener myFocusListener;
    // Our project's variables:
    //private Factory myFactory;

    /**
     * Construct demo with a title that will appear in the title bar. Language
     * controls which properties file is read to generate the button text.
     * 
     * Note, this constructor builds the entire GUI and displays it --- leaving
     * no flexibility for users. Not necessarily the best practice.
     * 
     * @param title title that appears in the Frame window's title bar
     * @param language language in which to display messages
     */
    public Canvas (String title, String language) {
        // set properties of frame
        setTitle(title);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        myChooser = new JFileChooser(System.getProperties().getProperty("user.dir"));

        // create and arrange sub-parts of the GUI
        myResources = ResourceBundle.getBundle("resources." + language);
        makeListeners();
        getContentPane().add(makeGraph(), BorderLayout.SOUTH);
        makeMenus();

        myFactory = new Factory();

        // size and display the GUI
        pack();
        setVisible(true);
    }

    /**
     * Display any string message in the main text area.
     * 
     * @param message message to display
     */
    public void showMessage (String message) {
        myTextArea.append(message + "\n");
        myTextArea.setCaretPosition(myTextArea.getText().length());
    }

    /**
     * Display any string message in a popup error dialog.
     * 
     * @param message message to display
     */
    public void showError (String message) {
        JOptionPane.showMessageDialog(this, message,
                                      "Input Error", JOptionPane.ERROR_MESSAGE);
    }

    /**
     * Create all the listeners so they can be later assigned to specific
     * components.
     * 
     * Note, since these classes will not ever be used by any other class, make
     * them inline (i.e., as anonymous inner classes) --- saves making a
     * separate file for one line of actual code.
     */
    protected void makeListeners () {
        myActionListener = new ActionListener() {
            @Override
            public void actionPerformed (ActionEvent e) { }
        };
        myKeyListener = new KeyListener() {
            @Override
            public void keyPressed (KeyEvent e) { }
            @Override
            public void keyReleased (KeyEvent e) { }
            @Override
            public void keyTyped (KeyEvent e) { }
        };
        myMouseListener = new MouseListener() {
            @Override
            public void mouseClicked (MouseEvent e) { }
            @Override
            public void mouseEntered (MouseEvent e) { }
            @Override
            public void mouseExited (MouseEvent e) { }
            @Override
            public void mousePressed (MouseEvent e) { }
            @Override
            public void mouseReleased (MouseEvent e) { }
        };
        myMouseMotionListener = new MouseMotionListener() {
            @Override
            public void mouseDragged (MouseEvent e) { }
            @Override
            public void mouseMoved (MouseEvent e) { }
        };
        myFocusListener = new FocusListener() {
            @Override
            public void focusGained (FocusEvent e) { }
            @Override
            public void focusLost (FocusEvent e) { }
        };
    }
    /**
     * Create an graph area. Defaults to a blank scatterplot.
     */
    protected JComponent makeGraph () {
        Dimension graphSize = new Dimension(GRAPH_WIDTH, GRAPH_HIGHT);
        myAxis = new ScatterPlot(graphSize);
        myGraph = myAxis;
        return myGraph;
    }

    /**
     * Create a menu to appear at the top of the frame, usually File, Edit, App
     * Specific Actions, Help
     */
    protected void makeMenus () {
        JMenuBar bar = new JMenuBar();
        bar.add(makeFileMenu());
        setJMenuBar(bar);
    }

    /**
     * Create an input area for the user --- textfield for text, buttons for
     * starting actions
     */
    protected JComponent makeInput () {
        JPanel result = new JPanel();
        result.add(makeTextField());
        result.add(makeButton());
        result.add(makeClear());
        return result;
    }

    /**
     * Create a display area for showing out to the user, since it may display
     * lots of text, make it automatically scroll when needed
     */
    protected JComponent makeDisplay () {
        // create with size in rows and columns
        myTextArea = new JTextArea(FIELD_SIZE, FIELD_SIZE);
        myTextArea.addMouseListener(myMouseListener);
        myTextArea.addMouseMotionListener(myMouseMotionListener);
        return new JScrollPane(myTextArea);
    }

    protected AbstractAction makeFileMenuParts(final String optionToMake) {
        return new AbstractAction(myResources.getString(optionToMake)) {
            @Override
            public void actionPerformed (ActionEvent e) {
                int response = myChooser.showOpenDialog(null);
                if (response == JFileChooser.APPROVE_OPTION) {
                    try {
                        loadData(myChooser.getSelectedFile(),
                                myResources.getString(optionToMake));
                    }
                    catch (AxisError e1) {
                        e1.printStackTrace();
                    }
                }
            }
        };
    }
    /**
     * Create a menu that will pop up when the menu button is pressed in the
     * frame. File menu usually contains Open, Save, and Exit
     * 
     * Note, since these classes will not ever be used by any other class, make
     * them inline (i.e., as anonymous inner classes) --- saves making a
     * separate file for one line of actual code.
     */
    protected JMenu makeFileMenu () {
        JMenu result = new JMenu(myResources.getString("FileMenu"));
        result.add(makeFileMenuParts(SCATTER_OPTION));
        result.add(makeFileMenuParts(LINE_OPTION));
        result.add(new JSeparator());
        result.add(new AbstractAction(myResources.getString("QuitCommand")) {
            @Override
            public void actionPerformed (ActionEvent e) {
                System.exit(0);
            }
        });
        return result;
    }
    protected void loadData (File file, String axisType) throws AxisError {
        getContentPane().remove(myGraph);
        Dimension graphSize = new Dimension(GRAPH_WIDTH, GRAPH_HIGHT);
        if (axisType == myResources.getString(SCATTER_OPTION)) {
            myAxis = new ScatterPlot(graphSize);
        }
        else if (axisType == myResources.getString(LINE_OPTION)) {
            myAxis = new LinePlot(graphSize);
        }
        else {
            throw new AxisError("Something went wrong! Trying to load a nonexistant axis type!");
        }
        myAxis.loadDataSet(myFactory.createDataSet(file));
        myGraph = myAxis;
        getContentPane().add(myGraph, BorderLayout.SOUTH);
        this.paintAll(getGraphics());
    }
    /**
     * Create a standard text field (a single line that responds to enter being
     * pressed as an ActionEvent) that listens for a variety of kinds of events
     */
    protected JTextField makeTextField () {
        JTextField result = new JTextField(FIELD_SIZE);
        result.addKeyListener(myKeyListener);
        result.addFocusListener(myFocusListener);
        result.addActionListener(myActionListener);
        return result;
    }

    /**
     * Create a standard button (a rectangular area that respondes to mouse
     * press and release within its bounds) that listens for a variety of kinds
     * of events
     */
    protected JButton makeButton () {
        JButton result = new JButton(myResources.getString("ActionCommand"));
        result.addActionListener(myActionListener);
        result.addKeyListener(myKeyListener);
        result.addMouseListener(myMouseListener);
        return result;
    }

    /**
     * Create a button whose action is to clear the display area when pressed.
     * 
     * Note, since this class will not ever be used by any other class, make it
     * inline (i.e., as anonymous inner classes) --- saves making a separate
     * file for one line of actual code.
     */
    protected JButton makeClear () {
        JButton result = new JButton(myResources.getString("ClearCommand"));
        result.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed (ActionEvent e) {
                myTextArea.setText("");
            }
        });
        return result;
    }

    /**
     * Java starts the program here and does not end until GUI goes away
     * 
     * @param args command-line arguments
     */
    public static void main (String[] args) {
        new Canvas("Event Demo", "English");
    }
}
